package cn.net.mugui.net.user;

import java.util.Arrays;

import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.util.encoders.Hex;

import com.mugui.base.base.Autowired;
import com.mugui.base.base.Component;
import com.mugui.base.client.net.bean.Message;

import cn.net.mugui.net.conf.SysConf;
import cn.net.mugui.net.dao.Dao;
import cn.net.mugui.net.key.ECKey;
import cn.net.mugui.net.key.Hash;
import cn.net.mugui.net.key.SymmEncoder;
import cn.net.mugui.net.key.utils.Base58;
import cn.net.mugui.net.key.utils.ByteArray;
import cn.net.mugui.net.key.utils.Utils;
import cn.net.mugui.net.p2p.ServerAttr;
import lombok.Getter;

/**
 * 用户工具
 *
 * @author 木鬼
 */
@Component
public class SelfUtil {

    /**
     * 通过密码登录成功
     */
    public static final int MESSAGE_TYPE_1 = 1;
    /**
     * 导入私钥成功
     */
    public static final int MESSAGE_TYPE_2 = 2;
    /**
     * 恢复并更新账号成功
     */
    public static final int MESSAGE_TYPE_3 = 3;
    /**
     * 创建新私钥成功
     */
    public static final int MESSAGE_TYPE_4 = 4;
    @Autowired
    private SysConf sysConf;
    @Autowired
    private Dao dao;
    @Getter
    private String pwd = null;

    /**
     * 创建一个用户
     *
     * @param pwd
     * @return
     * @author 木鬼
     */
    public Message createUser(String pwd) {
        this.pwd = pwd;
        SelfBean selfBean = null;
        String self_id = sysConf.value("self_id");
        if (pwd.length() == 64) {
            if (StringUtils.isBlank(self_id)) {
                ECKey fromPrivate = ECKey.fromPrivate(Hex.decode(pwd));
                byte[] passwordHash = getPasswordHash(this.pwd = pwd.substring(0, 10));
                if (passwordHash == null) {
                    return Message.error("私钥导入失败");
                }
                String pwdAsc = ByteArray.toHexString(passwordHash);
                selfBean = newUser(fromPrivate, pwdAsc);
                ServerAttr.self = selfBean;
                return Message.ok(selfBean, "导入私钥成功").setType(MESSAGE_TYPE_2);
            } else {
                ECKey fromPrivate = ECKey.fromPrivate(Hex.decode(pwd));
                byte[] passwordHash = getPasswordHash(this.pwd = pwd.substring(0, 10));
                if (passwordHash == null) {
                    return Message.error("私钥导入失败");
                }
                String pwdAsc = ByteArray.toHexString(passwordHash);
                selfBean = updateUser(selfBean = (SelfBean) dao.get(new SelfBean().setId(Integer.parseInt(self_id))),
                        fromPrivate, pwdAsc);
                ServerAttr.self = selfBean;
                return Message.ok(selfBean, "恢复并重置密码成功").setType(MESSAGE_TYPE_3);
            }
        }
        byte[] passwordHash = getPasswordHash(pwd);
        if (passwordHash == null) {
            return Message.error("密码简单化");
        }
        String pwdAsc = ByteArray.toHexString(passwordHash);
        if (StringUtils.isBlank(self_id)) {
            selfBean = newUser(pwdAsc);
            ServerAttr.self = selfBean;
            return Message.ok(selfBean, "创建成功").setType(MESSAGE_TYPE_4);
        } else {
            selfBean = (SelfBean) new SelfBean().setId(Integer.parseInt(self_id));
            selfBean = dao.select(selfBean);
            String private_key = selfBean.getPrivate_key();
            byte[] decodeHex = Hex.decode(private_key);
            byte[] aes128EcbDec = SymmEncoder.AES128EcbDec(decodeHex, passwordHash);
            ECKey fromPrivate = ECKey.fromPrivate(aes128EcbDec);
            String encode58Check = encode58Check(fromPrivate.getAddress());
            if (selfBean.getAddress().equals(encode58Check)) {
                ServerAttr.self = selfBean;
                return Message.ok(selfBean, "登录成功").setType(MESSAGE_TYPE_1);
            }
            return Message.error("密码错误，登录失败");
        }
    }

    /**
     * 更新用户信息
     *
     * @param selfBean
     * @param ecKey
     * @param pwdAsc
     * @return
     * @author 木鬼
     */
    private SelfBean updateUser(SelfBean selfBean, ECKey ecKey, String pwdAsc) {
		if (selfBean == null) {
			selfBean = newUser(ecKey, pwdAsc);
		}
        initUser(selfBean, ecKey, pwdAsc);
        dao.updata(selfBean);
        return selfBean;
    }

    /**
     * 初始化一个SelfBean
     *
     * @param selfBean
     * @param ecKey
     * @param pwdAsc
     * @author 木鬼
     */
    private void initUser(SelfBean selfBean, ECKey ecKey, String pwdAsc) {
        byte[] aes128EcbEnc = SymmEncoder.AES128EcbEnc(ecKey.getPrivKeyBytes(), ByteArray.fromHexString(pwdAsc));
        selfBean.setPrivate_key(ByteArray.toHexString(aes128EcbEnc));
        selfBean.setPublic_key(ByteArray.toHexString(ecKey.getPubKey()));
        selfBean.setAddress(encode58Check(ecKey.getAddress()));
    }

    public String getPrivateKey() {
        if (StringUtils.isBlank(pwd)) {
            return null;
        }
        byte[] passwordHash = getPasswordHash(pwd);
        if (passwordHash == null) {
            return null;
        }
        String private_key = ServerAttr.self.getPrivate_key();
        byte[] decodeHex = Hex.decode(private_key);
        byte[] aes128EcbDec = SymmEncoder.AES128EcbDec(decodeHex, passwordHash);
        ECKey fromPrivate = ECKey.fromPrivate(aes128EcbDec);
        return ByteArray.toHexString(fromPrivate.getPrivKeyBytes());
    }

    /**
     * 初始化一个用户
     *
     * @param pwdAsc
     * @return
     * @author 木鬼
     */
    private SelfBean newUser(String pwdAsc) {
        ECKey ecKey = new ECKey(Utils.getRandom());
        return newUser(ecKey, pwdAsc);
    }

    private SelfBean newUser(ECKey ecKey, String pwdAsc) {
        SelfBean selfBean = new SelfBean();
        initUser(selfBean, ecKey, pwdAsc);
        selfBean.setName("self-mugui");
        selfBean = dao.save(selfBean);
        sysConf.save("self_id", selfBean.getId().toString());
        return selfBean;
    }

    public String encode58Check(byte[] input) {
        byte[] hash0 = Hash.sha256(input);
        byte[] hash1 = Hash.sha256(hash0);
        byte[] inputCheck = new byte[input.length + 4];
        System.arraycopy(input, 0, inputCheck, 0, input.length);
        System.arraycopy(hash1, 0, inputCheck, input.length, 4);
        return Base58.encode(inputCheck);
    }

    public byte[] getPasswordHash(String password) {
        if (!isPasswordValid(password)) {
            return null;
        }
        byte[] pwd;
        pwd = Hash.sha256(password.getBytes());
        pwd = Hash.sha256(pwd);
        pwd = Arrays.copyOfRange(pwd, 0, 16);
        return pwd;
    }

    public boolean isPasswordValid(String password) {
        if (StringUtils.isEmpty(password)) {
            return false;
        }
        if (password.length() < 6) {
            return false;
        }
        return !password.contains("\\s");
    }
}
